#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include <curl/curl.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <mpv/client.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>

#include <libgen.h>
#include <limits.h>
#include <openssl/evp.h>
#include <openssl/md5.h>

#define CACHE_DIR ".cache/peruere"
#define CACHE_INDEX "index"
static char *video_file = NULL;
static char *video_url = NULL;
static char *geometry = "1920x1080+0+0";
static int keep_cache = 0;
static int clean_cache = 0;
static int temp_fd = -1;
static char temp_path[PATH_MAX] = {0};
static char cache_path[PATH_MAX] = {0};
static mpv_handle *mpv_inst = NULL;
static pthread_t mpv_event_thread;
static volatile int quit_flag = 0;
static CURL *curl_handle = NULL;

static curl_off_t download_total = 0;
static curl_off_t download_current = 0;
static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;

static void print_help(const char *prog_name) {
  fprintf(stdout, "用法: %s [选项]\n", prog_name);
  fprintf(stdout, "将视频作为桌面背景循环播放\n\n");
  fprintf(stdout, "选项:\n");
  fprintf(stdout, "  -f, --file <路径>    本地视频文件路径（与--url二选一）\n");
  fprintf(stdout, "  -u, --url <链接>     网络视频URL（与--file二选一）\n");
  fprintf(stdout, "  -g, --geometry <格式> 窗口尺寸与位置（格式: 宽x高+X偏移+Y偏移，默认1920x1080+0+0）\n");
  fprintf(stdout, "  -k, --keep           缓存网络视频（用于--url，下次播放相同URL将复用缓存）\n");
  fprintf(stdout, "  -c, --clean-cache    清理所有缓存文件（执行后退出）\n");
  fprintf(stdout, "  -h, --help           显示帮助信息并退出\n");
  fprintf(stdout, "\n示例:\n");
  fprintf(stdout, "  %s --file ~/video.mp4\n", prog_name);
  fprintf(stdout, "  %s --url https://example.com/video.mp4 -k\n", prog_name);
  fprintf(stdout, "  %s --clean-cache\n", prog_name);
}

static int parse_geometry(const char *geom, int *width, int *height, int *x, int *y) {
  if (sscanf(geom, "%dx%d+%d+%d", width, height, x, y) != 4) {
    fprintf(stderr, "[ERROR] geometry格式无效：%s（正确格式：宽x高+X+Y）\n", geom);
    return -1;
  }
  if (*width <= 0 || *height <= 0) {
    fprintf(stderr, "[ERROR] 宽高必须为正数：宽=%d 高=%d\n", *width, *height);
    return -1;
  }
  fprintf(stdout, "[INFO] 窗口配置：宽=%d 高=%d 偏移X=%d 偏移Y=%d\n", *width, *height, *x, *y);
  return 0;
}

static void url_to_md5(const char *url, char *md5_str) {
  EVP_MD_CTX *ctx = EVP_MD_CTX_new();
  if (!ctx) {
    fprintf(stderr, "[ERROR] 创建EVP上下文失败\n");
    memset(md5_str, 0, 33);
    return;
  }

  if (EVP_DigestInit_ex(ctx, EVP_md5(), NULL) != 1) {
    fprintf(stderr, "[ERROR] 初始化MD5失败\n");
    EVP_MD_CTX_free(ctx);
    memset(md5_str, 0, 33);
    return;
  }

  if (EVP_DigestUpdate(ctx, url, strlen(url)) != 1) {
    fprintf(stderr, "[ERROR] 更新MD5哈希失败\n");
    EVP_MD_CTX_free(ctx);
    memset(md5_str, 0, 33);
    return;
  }

  unsigned char md5_hash[EVP_MAX_MD_SIZE];
  unsigned int md5_len;
  if (EVP_DigestFinal_ex(ctx, md5_hash, &md5_len) != 1 || md5_len != MD5_DIGEST_LENGTH) {
    fprintf(stderr, "[ERROR] 计算MD5哈希失败\n");
    EVP_MD_CTX_free(ctx);
    memset(md5_str, 0, 33);
    return;
  }
  EVP_MD_CTX_free(ctx);

  for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
    sprintf(md5_str + 2 * i, "%02x", md5_hash[i]);
  }
  md5_str[32] = '\0';
  fprintf(stdout, "[INFO] URL=%s MD5=%s\n", url, md5_str);
}

static int init_cache_dir() {
  char *home = getenv("HOME");
  if (!home) {
    fprintf(stderr, "[ERROR] 无法获取用户主目录（HOME环境变量未设置）\n");
    return -1;
  }

  char full_cache_dir[PATH_MAX];
  snprintf(full_cache_dir, PATH_MAX, "%s/%s", home, CACHE_DIR);
  fprintf(stdout, "[INFO] 缓存目录：%s\n", full_cache_dir);

  char *dir = strdup(full_cache_dir);
  char *p = dir;
  while (*p) {
    if (*p == '/') {
      *p = '\0';
      if (strlen(dir) > 0) {
        if (mkdir(dir, 0755) != 0 && errno != EEXIST) {
          fprintf(stderr, "[ERROR] 创建目录失败：%s 原因：%s\n", dir, strerror(errno));
          free(dir);
          return -1;
        }
      }
      *p = '/';
    }
    p++;
  }

  if (mkdir(full_cache_dir, 0755) != 0 && errno != EEXIST) {
    fprintf(stderr, "[ERROR] 创建缓存目录失败：%s 原因：%s\n", full_cache_dir, strerror(errno));
    free(dir);
    return -1;
  }
  free(dir);
  return 0;
}

static int remove_dir(const char *path) {
  DIR *dir = opendir(path);
  if (!dir) {
    fprintf(stderr, "[ERROR] 打开目录失败：%s 原因：%s\n", path, strerror(errno));
    return -1;
  }

  struct dirent *entry;
  while ((entry = readdir(dir)) != NULL) {
    if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
      continue;
    }

    char full_path[PATH_MAX];
    snprintf(full_path, PATH_MAX, "%s/%s", path, entry->d_name);

    struct stat st;
    if (stat(full_path, &st) != 0) {
      fprintf(stderr, "[WARNING] 获取文件状态失败：%s 原因：%s\n", full_path, strerror(errno));
      continue;
    }

    if (S_ISDIR(st.st_mode)) {
      if (remove_dir(full_path) != 0) {
        closedir(dir);
        return -1;
      }
    } else {
      if (unlink(full_path) != 0) {
        fprintf(stderr, "[WARNING] 删除文件失败：%s 原因：%s\n", full_path, strerror(errno));
      } else {
        fprintf(stdout, "[INFO] 已删除缓存文件：%s\n", full_path);
      }
    }
  }

  closedir(dir);

  if (rmdir(path) != 0) {
    fprintf(stderr, "[ERROR] 删除目录失败：%s 原因：%s\n", path, strerror(errno));
    return -1;
  }
  fprintf(stdout, "[INFO] 已删除缓存目录：%s\n", path);
  return 0;
}

static void clean_all_cache() {
  char *home = getenv("HOME");
  if (!home) {
    fprintf(stderr, "[ERROR] 无法获取用户主目录，清理缓存失败\n");
    return;
  }

  char full_cache_dir[PATH_MAX];
  snprintf(full_cache_dir, PATH_MAX, "%s/%s", home, CACHE_DIR);
  fprintf(stdout, "[INFO] 开始清理缓存：%s\n", full_cache_dir);

  struct stat st;
  if (stat(full_cache_dir, &st) != 0) {
    if (errno == ENOENT) {
      fprintf(stdout, "[INFO] 缓存目录不存在，无需清理\n");
    } else {
      fprintf(stderr, "[ERROR] 访问缓存目录失败：%s 原因：%s\n", full_cache_dir, strerror(errno));
    }
    return;
  }

  if (!S_ISDIR(st.st_mode)) {
    fprintf(stderr, "[ERROR] %s 不是目录，清理失败\n", full_cache_dir);
    return;
  }

  if (remove_dir(full_cache_dir) == 0) {
    fprintf(stdout, "[INFO] 缓存清理完成\n");
  } else {
    fprintf(stderr, "[ERROR] 缓存清理失败\n");
  }
}

static int find_cached_url(const char *url, char *cache_path) {
  char *home = getenv("HOME");
  if (!home) {
    fprintf(stderr, "[ERROR] 无法获取用户主目录\n");
    return -1;
  }

  char index_path[PATH_MAX];
  snprintf(index_path, PATH_MAX, "%s/%s/%s", home, CACHE_DIR, CACHE_INDEX);
  fprintf(stdout, "[INFO] 查找缓存索引：%s\n", index_path);

  FILE *index = fopen(index_path, "r");
  if (!index) {
    fprintf(stdout, "[INFO] 缓存索引文件不存在\n");
    return -1;
  }

  char line[1024];
  while (fgets(line, sizeof(line), index)) {
    char stored_url[1024], stored_md5[33];
    if (sscanf(line, "%32s %s", stored_md5, stored_url) == 2) {
      if (strcmp(stored_url, url) == 0) {
        snprintf(cache_path, PATH_MAX, "%s/%s/%s.mp4", home, CACHE_DIR, stored_md5);
        fclose(index);
        fprintf(stdout, "[INFO] 找到缓存文件：%s\n", cache_path);
        return 0;
      }
    }
  }
  fclose(index);
  fprintf(stdout, "[INFO] 未找到URL对应的缓存：%s\n", url);
  return -1;
}

static int add_to_cache_index(const char *url, const char *md5) {
  if (init_cache_dir() != 0) {
    return -1;
  }

  char *home = getenv("HOME");
  char index_path[PATH_MAX];
  snprintf(index_path, PATH_MAX, "%s/%s/%s", home, CACHE_DIR, CACHE_INDEX);

  char existing_path[PATH_MAX];
  if (find_cached_url(url, existing_path) == 0) {
    fprintf(stdout, "[INFO] URL已存在于缓存索引：%s\n", url);
    return 0;
  }

  FILE *index = fopen(index_path, "a");
  if (!index) {
    fprintf(stderr, "[ERROR] 打开缓存索引失败：%s 原因：%s\n", index_path, strerror(errno));
    return -1;
  }
  fprintf(index, "%s %s\n", md5, url);
  fclose(index);
  fprintf(stdout, "[INFO] 已添加到缓存索引：%s -> %s\n", md5, url);
  return 0;
}

static void signal_handler(int sig) {
  fprintf(stdout, "\n[INFO] 收到退出信号（%d），正在终止...\n", sig);
  quit_flag = 1;

  if (curl_handle) {
    curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 1L);
    fprintf(stdout, "[INFO] 已中断curl下载\n");
  }
}

static int peruere_xferinfo_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
  (void)clientp;
  (void)ultotal;
  (void)ulnow;

  if (quit_flag) {
    fprintf(stdout, "[INFO] 下载中断回调触发\n");
    return 1;
  }

  pthread_mutex_lock(&progress_mutex);
  download_total = dltotal;
  download_current = dlnow;
  pthread_mutex_unlock(&progress_mutex);

  if (dltotal > 0) {
    int percent = (int)((double)dlnow / dltotal * 100);
    fprintf(stderr, "\r[DOWNLOAD] %3d%% | %6.2f MB / %6.2f MB", percent, (double)dlnow / 1024 / 1024, (double)dltotal / 1024 / 1024);
  } else {
    fprintf(stderr, "\r[DOWNLOAD] 已接收：%6.2f MB", (double)dlnow / 1024 / 1024);
  }
  fflush(stderr);
  return 0;
}

static size_t peruere_write_callback(void *ptr, size_t size, size_t nmemb, void *stream) {
  if (quit_flag) {
    fprintf(stdout, "[INFO] 写入回调中断\n");
    return 0;
  }
  int fd = *(int *)stream;
  size_t written = write(fd, ptr, size * nmemb);
  if (written != size * nmemb) {
    fprintf(stderr, "[WARNING] 写入文件失败：实际写入%d 预期%d\n", (int)written, (int)(size * nmemb));
  }
  return written;
}

static int download_url(const char *url, char **play_path) {
  if (find_cached_url(url, cache_path) == 0) {
    struct stat st;
    if (stat(cache_path, &st) == 0 && st.st_size > 0) {
      *play_path = cache_path;
      return 0;
    } else {
      fprintf(stdout, "[INFO] 缓存文件无效，重新下载：%s\n", cache_path);
      unlink(cache_path);
    }
  }

  fprintf(stdout, "[INFO] 开始下载URL：%s\n", url);
  curl_handle = curl_easy_init();
  if (!curl_handle) {
    fprintf(stderr, "[ERROR] curl初始化失败\n");
    return -1;
  }

  int fd = -1;
  char *save_path = NULL;
  char md5_str[33] = {0};
  char temp_template[PATH_MAX];

  if (keep_cache) {
    url_to_md5(url, md5_str);
    if (init_cache_dir() != 0) {
      curl_easy_cleanup(curl_handle);
      return -1;
    }
    char *home = getenv("HOME");
    snprintf(cache_path, PATH_MAX, "%s/%s/%s.mp4", home, CACHE_DIR, md5_str);
    fd = open(cache_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    save_path = cache_path;
    fprintf(stdout, "[INFO] 缓存模式：保存至 %s\n", save_path);
  } else {
    snprintf(temp_template, PATH_MAX, "/tmp/peruere-XXXXXX");
    fd = mkstemp(temp_template);
    if (fd < 0) {
      fprintf(stderr, "[ERROR] 创建临时文件失败（模板：%s）原因：%s\n", temp_template, strerror(errno));
      curl_easy_cleanup(curl_handle);
      return -1;
    }
    snprintf(temp_path, PATH_MAX, "%s.mp4", temp_template);
    if (rename(temp_template, temp_path) != 0) {
      strncpy(temp_path, temp_template, PATH_MAX - 1);
      fprintf(stdout, "[WARNING] 临时文件重命名失败，使用原名称：%s\n", temp_path);
    }
    save_path = temp_path;
    fprintf(stdout, "[INFO] 临时模式：保存至 %s\n", save_path);
  }

  if (fd < 0) {
    fprintf(stderr, "[ERROR] 创建文件失败：%s 原因：%s\n", save_path, strerror(errno));
    curl_easy_cleanup(curl_handle);
    return -1;
  }

  curl_easy_setopt(curl_handle, CURLOPT_URL, url);
  curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
  curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, peruere_write_callback);
  curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &fd);
  curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L);
  curl_easy_setopt(curl_handle, CURLOPT_XFERINFOFUNCTION, peruere_xferinfo_callback);
  curl_easy_setopt(curl_handle, CURLOPT_XFERINFODATA, NULL);
  curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 10L);
  curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 300L);
  curl_easy_setopt(curl_handle, CURLOPT_LOW_SPEED_LIMIT, 1024);
  curl_easy_setopt(curl_handle, CURLOPT_LOW_SPEED_TIME, 10);

  CURLcode res = curl_easy_perform(curl_handle);
  fprintf(stderr, "\n");
  close(fd);
  curl_easy_cleanup(curl_handle);
  curl_handle = NULL;

  if (quit_flag) {
    fprintf(stdout, "[INFO] 下载被用户中断\n");
    if (!keep_cache) {
      unlink(save_path);
      fprintf(stdout, "[INFO] 已删除临时文件：%s\n", save_path);
    }
    return -1;
  }

  if (res != CURLE_OK) {
    fprintf(stderr, "[ERROR] 下载失败：%s 原因：%s\n", url, curl_easy_strerror(res));
    unlink(save_path);
    fprintf(stdout, "[INFO] 已删除不完整文件：%s\n", save_path);
    return -1;
  }

  if (keep_cache && strlen(md5_str) > 0) {
    add_to_cache_index(url, md5_str);
  }

  fprintf(stdout, "[INFO] 下载完成：%s 大小：%.2f MB\n", save_path, (double)download_current / 1024 / 1024);
  *play_path = save_path;
  return 0;
}

static void cleanup_temp_file(void) {
  if (temp_fd >= 0) {
    close(temp_fd);
    temp_fd = -1;
    fprintf(stdout, "[INFO] 已关闭临时文件句柄\n");
  }
  if (strlen(temp_path) > 0 && access(temp_path, F_OK) == 0) {
    if (unlink(temp_path) == 0) {
      fprintf(stdout, "[INFO] 已清理临时文件：%s\n", temp_path);
    } else {
      fprintf(stderr, "[WARNING] 删除临时文件失败：%s 原因：%s\n", temp_path, strerror(errno));
    }
    temp_path[0] = '\0';
  }
}

static void *mpv_event_loop(void *arg) {
  (void)arg;
  fprintf(stdout, "[INFO] mpv事件线程启动\n");
  while (!quit_flag) {
    mpv_event *event = mpv_wait_event(mpv_inst, 100);
    if (!event) continue;

    switch (event->event_id) {
      case MPV_EVENT_LOG_MESSAGE: {
        mpv_event_log_message *msg = (mpv_event_log_message *)event->data;
        fprintf(stdout, "[MPV-LOG] [%s] %s\n", msg->prefix, msg->text);
        break;
      }
      case MPV_EVENT_SHUTDOWN:
        fprintf(stdout, "[INFO] mpv已关闭\n");
        quit_flag = 1;
        break;
      case MPV_EVENT_END_FILE:
        fprintf(stdout, "[INFO] 视频播放结束，循环中...\n");
        break;
      case MPV_EVENT_FILE_LOADED:
        fprintf(stdout, "[INFO] 视频文件加载成功\n");
        break;
      default:
        fprintf(stdout, "[INFO] mpv事件：%d\n", event->event_id);
        break;
    }
  }
  fprintf(stdout, "[INFO] mpv事件线程退出\n");
  return NULL;
}

static Window create_x11_window(Display **display, int width, int height, int x, int y) {
  *display = XOpenDisplay(NULL);
  if (!*display) {
    fprintf(stderr, "[ERROR] 无法打开X11显示\n");
    return None;
  }
  fprintf(stdout, "[INFO] X11显示打开成功：%s\n", DisplayString(*display));

  Window root = DefaultRootWindow(*display);
  XSetWindowAttributes attrs = {0};
  attrs.background_pixmap = ParentRelative;
  attrs.backing_store = Always;
  attrs.override_redirect = True;

  Window win = XCreateWindow(*display, root, x, y, width, height, 0,
                             DefaultDepth(*display, DefaultScreen(*display)),
                             InputOutput,
                             DefaultVisual(*display, DefaultScreen(*display)),
                             CWOverrideRedirect | CWBackingStore, &attrs);
  if (win == None) {
    fprintf(stderr, "[ERROR] 创建X11窗口失败\n");
    XCloseDisplay(*display);
    *display = NULL;
    return None;
  }
  fprintf(stdout, "[INFO] X11窗口创建成功：句柄=%lu\n", (unsigned long)win);

  XClassHint class_hint = {.res_name = "peruere", .res_class = "peruere"};
  XSetClassHint(*display, win, &class_hint);

  Atom net_wm_window_type = XInternAtom(*display, "_NET_WM_WINDOW_TYPE", False);
  Atom net_wm_window_type_desktop = XInternAtom(*display, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
  XChangeProperty(*display, win, net_wm_window_type, XA_ATOM, 32,
                  PropModeReplace, (unsigned char *)&net_wm_window_type_desktop, 1);

  Atom net_wm_state = XInternAtom(*display, "_NET_WM_STATE", False);
  Atom net_wm_state_below = XInternAtom(*display, "_NET_WM_STATE_BELOW", False);
  XChangeProperty(*display, win, net_wm_state, XA_ATOM, 32, PropModeAppend,
                  (unsigned char *)&net_wm_state_below, 1);

  Atom net_wm_state_sticky = XInternAtom(*display, "_NET_WM_STATE_STICKY", False);
  XChangeProperty(*display, win, net_wm_state, XA_ATOM, 32, PropModeAppend,
                  (unsigned char *)&net_wm_state_sticky, 1);

  Atom motif_wm_hints = XInternAtom(*display, "_MOTIF_WM_HINTS", False);
  if (motif_wm_hints != None) {
    long hints[5] = {2, 0, 0, 0, 0};
    XChangeProperty(*display, win, motif_wm_hints, motif_wm_hints, 32,
                    PropModeReplace, (unsigned char *)hints, 5);
  }

  XStoreName(*display, win, "peruere");

  Region region = XCreateRegion();
  XShapeCombineRegion(*display, win, ShapeInput, 0, 0, region, ShapeSet);
  XDestroyRegion(region);

  XMapWindow(*display, win);
  XLowerWindow(*display, win);
  XFlush(*display);
  fprintf(stdout, "[INFO] X11窗口已显示并置底\n");

  return win;
}

int main(int argc, char *argv[]) {
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = signal_handler;
  sigaction(SIGINT, &sa, NULL);
  sigaction(SIGTERM, &sa, NULL);
  atexit(cleanup_temp_file);

  fprintf(stdout, "[INFO] 程序启动：%s\n", argv[0]);

  static const struct option long_options[] = {
    {"file", required_argument, NULL, 'f'},
    {"url", required_argument, NULL, 'u'},
    {"geometry", required_argument, NULL, 'g'},
    {"keep", no_argument, NULL, 'k'},
    {"clean-cache", no_argument, NULL, 'c'},
    {"help", no_argument, NULL, 'h'},
    {NULL, 0, NULL, 0}
  };

  int opt;
  while ((opt = getopt_long(argc, argv, "f:u:g:kch", long_options, NULL)) != -1) {
    switch (opt) {
      case 'f':
        video_file = optarg;
        fprintf(stdout, "[INFO] 已指定本地文件：%s\n", video_file);
        break;
      case 'u':
        video_url = optarg;
        fprintf(stdout, "[INFO] 已指定网络URL：%s\n", video_url);
        break;
      case 'g':
        geometry = optarg;
        fprintf(stdout, "[INFO] 已指定窗口配置：%s\n", geometry);
        break;
      case 'k':
        keep_cache = 1;
        fprintf(stdout, "[INFO] 已启用缓存模式\n");
        break;
      case 'c':
        clean_cache = 1;
        fprintf(stdout, "[INFO] 已触发缓存清理模式\n");
        break;
      case 'h':
        print_help(argv[0]);
        return 0;
      case '?':
        fprintf(stderr, "[ERROR] 未知选项，请使用--help查看帮助\n");
        return 1;
      default:
        abort();
    }
  }

  if (clean_cache) {
    clean_all_cache();
    return 0;
  }

  if ((!video_file && !video_url) || (video_file && video_url)) {
    fprintf(stderr, "[ERROR] 必须指定--file（本地文件）或--url（网络URL）中的一个\n");
    fprintf(stderr, "[INFO] 使用--help查看详细用法\n");
    return 1;
  }

  int win_width, win_height, win_x, win_y;
  if (parse_geometry(geometry, &win_width, &win_height, &win_x, &win_y) != 0) {
    return 1;
  }

  char *play_path = NULL;
  if (video_url) {
    if (download_url(video_url, &play_path) != 0) {
      fprintf(stderr, "[ERROR] 处理URL失败\n");
      return 1;
    }
  } else {
    play_path = video_file;
    struct stat st;
    if (stat(play_path, &st) != 0) {
      fprintf(stderr, "[ERROR] 本地文件不存在：%s 原因：%s\n", play_path, strerror(errno));
      return 1;
    }
    if (st.st_size == 0) {
      fprintf(stderr, "[ERROR] 本地文件为空：%s\n", play_path);
      return 1;
    }
    fprintf(stdout, "[INFO] 本地文件验证通过：%s 大小：%.2f MB\n", play_path, (double)st.st_size / 1024 / 1024);
  }

  Display *display = NULL;
  Window win = create_x11_window(&display, win_width, win_height, win_x, win_y);
  if (win == None) {
    fprintf(stderr, "[ERROR] X11窗口创建失败\n");
    return 1;
  }

  mpv_inst = mpv_create();
  if (!mpv_inst) {
    fprintf(stderr, "[ERROR] 创建mpv实例失败\n");
    XCloseDisplay(display);
    return 1;
  }
  fprintf(stdout, "[INFO] mpv实例创建成功\n");

  if (mpv_set_option_string(mpv_inst, "loop", "yes") < 0) {
    fprintf(stderr, "[ERROR] 设置循环播放失败\n");
    mpv_terminate_destroy(mpv_inst);
    XCloseDisplay(display);
    return 1;
  }
  if (mpv_set_option_string(mpv_inst, "x11-bypass-compositor", "yes") < 0) {
    fprintf(stderr, "[ERROR] 设置绕过compositor失败\n");
    mpv_terminate_destroy(mpv_inst);
    XCloseDisplay(display);
    return 1;
  }
  if (mpv_set_option_string(mpv_inst, "vo", "gpu") < 0) {
    fprintf(stderr, "[ERROR] 设置视频输出失败\n");
    mpv_terminate_destroy(mpv_inst);
    XCloseDisplay(display);
    return 1;
  }
  fprintf(stdout, "[INFO] mpv基础选项设置完成\n");

  int64_t wid = (int64_t)win;
  if (mpv_set_property(mpv_inst, "wid", MPV_FORMAT_INT64, &wid) < 0) {
    fprintf(stderr, "[ERROR] 绑定窗口句柄失败（wid=%ld）\n", wid);
    mpv_terminate_destroy(mpv_inst);
    XCloseDisplay(display);
    return 1;
  }
  fprintf(stdout, "[INFO] 已绑定mpv到X11窗口（wid=%ld）\n", wid);

  if (mpv_initialize(mpv_inst) < 0) {
    fprintf(stderr, "[ERROR] 初始化mpv失败\n");
    mpv_terminate_destroy(mpv_inst);
    XCloseDisplay(display);
    return 1;
  }
  mpv_request_log_messages(mpv_inst, "info");
  fprintf(stdout, "[INFO] mpv初始化完成\n");

  if (pthread_create(&mpv_event_thread, NULL, mpv_event_loop, NULL) != 0) {
    fprintf(stderr, "[ERROR] 创建mpv事件线程失败\n");
    mpv_terminate_destroy(mpv_inst);
    XCloseDisplay(display);
    return 1;
  }

  const char *cmd[] = {"loadfile", play_path, NULL};
  if (mpv_command_async(mpv_inst, 0, cmd) < 0) {
    fprintf(stderr, "[ERROR] 加载视频失败：%s\n", play_path);
    quit_flag = 1;
    pthread_join(mpv_event_thread, NULL);
    mpv_terminate_destroy(mpv_inst);
    XCloseDisplay(display);
    return 1;
  }
  fprintf(stdout, "[INFO] 已发送加载视频命令：%s\n", play_path);
  fprintf(stdout, "[INFO] 视频开始播放，按Ctrl+C退出...\n");

  while (!quit_flag) {
    sleep(1);
  }

  fprintf(stdout, "[INFO] 开始清理资源...\n");
  mpv_command_async(mpv_inst, 0, (const char *[]){"quit", NULL});
  pthread_join(mpv_event_thread, NULL);
  mpv_terminate_destroy(mpv_inst);
  XCloseDisplay(display);

  fprintf(stdout, "[INFO] 程序正常退出\n");
  return 0;
}
